package in.iqing.control.api;

import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import in.iqing.App;
import in.iqing.Constants;
import in.iqing.control.api.callback.BookListCallback;
import in.iqing.control.api.callback.CategoryListCallback;
import in.iqing.control.api.callback.ICallback;
import in.iqing.control.api.callback.LoginCallback;
import in.iqing.control.api.callback.ParagraphCallback;
import in.iqing.control.api.callback.VolumeCallback;
import in.iqing.control.api.callback.RecommendCallback;
import in.iqing.control.api.callback.RegisterCallback;
import in.iqing.control.api.callback.RequestCallback;
import in.iqing.control.api.volley.QingAuthedRequest;
import in.iqing.control.helper.LogHelper;
import in.iqing.model.sp.ApiSP;

public class ApiHelper {

    private static final String TAG = "ApiHelper";

    private static ApiHelper singleton;
    private RequestQueue requestQueue;

    public ApiHelper() {
        this.requestQueue = Volley.newRequestQueue(App.getInstance());
    }

    public static synchronized ApiHelper getSingleton() {
        if (singleton == null) {
            singleton = new ApiHelper();
        }

        return singleton;
    }

    public void cancel(Object tag) {
        requestQueue.cancelAll(tag);
    }

    public void onInitialize() {
    }

    private void get(Object tag, String url, ICallback callback) {
        LogHelper.warn(getClass(), url);

        callback.onStart();
        requestQueue.add(new QingAuthedRequest(Constants.USER_AGENT, Request.Method.GET, url, callback, callback).setTag(tag));
    }

    private void post(Object tag, String url, final Map<String, String> params, ICallback callback) {
        post(tag, url, DefaultRetryPolicy.DEFAULT_TIMEOUT_MS, params, callback);
    }

    private void post(Object tag, String url, int timeout, final Map<String, String> params, ICallback callback) {
        LogHelper.warn(getClass(), "url:" + url + " timeout:" + timeout);
        LogHelper.warn(getClass(), params.toString());

        callback.onStart();
        requestQueue.add(new QingAuthedRequest(Constants.USER_AGENT, Request.Method.POST, timeout, url, callback, callback) {

            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                return params;
            }
        }.setTag(tag));
    }

    private StringBuilder appendQuery(StringBuilder input, boolean hasQuery, String name, Object value) {
        if (!hasQuery) {
            input.append("?");
        } else {
            input.append("&");
        }
        return input.append(name + "=" + value);
    }

    public void getRecommend(Object tag, RecommendCallback callback) {
        get(tag, ApiSP.getRecommend(), callback);
    }

    public void getCategories(Object tag, CategoryListCallback callback) {
        // load all categories in one request
        get(tag, ApiSP.getCategory() + "/?limit=" + Constants.LIMIT_MAX, callback);
    }

    public void login(Object tag, String mobile, String password, LoginCallback callback) {
        HashMap<String, String> params = new HashMap<>();
        params.put("mobile", mobile);
        params.put("password", password);
        post(tag, ApiSP.getLogin(), params, callback);
    }

    public void requestVerify(Object tag, String mobile, RequestCallback callback) {
        HashMap<String, String> params = new HashMap<>();
        params.put("mobile", mobile);
        post(tag, ApiSP.getSms(), params, callback);
    }

    public void register(Object tag, String mobile, String code, String username, String password, RegisterCallback callback) {
        HashMap<String, String> params = new HashMap<>();
        params.put("mobile", mobile);
        params.put("code", code);
        params.put("username", username);
        params.put("password", password);
        post(tag, ApiSP.getRegister(), params, callback);
    }

    public void getCategoryContent(Object tag, int categoryId, int pageSize, int pageNo, BookListCallback callback) {
        get(tag, ApiSP.getCategory() + "/" + categoryId + "/book/?limit=" + pageSize + "&offset=" + (pageNo - 1) * pageSize, callback);
    }

    public void getAuthorBooks(Object tag, String author, int pageSize, int pageNo, BookListCallback callback) {
        try {
            author = URLEncoder.encode(author, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        get(tag, ApiSP.getAuthor() + "/" + author + "/?limit=" + pageSize + "&offset=" + (pageNo - 1) * pageSize, callback);
    }

    public void getPressBooks(Object tag, String press, int pageSize, int pageNo, BookListCallback callback) {
        try {
            press = URLEncoder.encode(press, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        get(tag, ApiSP.getPress() + "/" + press + "/?limit=" + pageSize + "&offset=" + (pageNo - 1) * pageSize, callback);
    }

    public void getVolume(Object tag, int bookId, VolumeCallback callback) {
        get(tag, ApiSP.getBook() + "/" + bookId + "/chapter/", callback);
    }

    public void getParagraph(Object tag, String contentUrl, ParagraphCallback callback) {
        get(tag, contentUrl + "?limit=" + Constants.LIMIT_MAX, callback);
    }

    public void getSearchResult(Object tag, String keyword, int pageSize, int pageNo, BookListCallback callback) {
        try {
            keyword = URLEncoder.encode(keyword, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        get(tag, ApiSP.getSearch() + "?q=" + keyword + "&field=title&limit=" + pageSize + "&offset=" + (pageNo - 1) * pageSize, callback);
    }

    public void getLatestUpdate(Object tag, int pageSize, int pageNo, BookListCallback callback) {
        get(tag, ApiSP.getLatestUpdate() + "?limit=" + pageSize + "&offset=" + (pageNo - 1) * pageSize, callback);
    }

}
